#!/usr/bin/python
# -*- coding: UTF-8 -*-
# @Time    : 2023/11/17 10:53
# @Author  : 飞飞
import os
import string
import random
from PIL import Image, ImageFont, ImageDraw, ImageFilter


# 图像验证码类
class ImageVerify:
    def __init__(self, length=4, width=107, height=50, size=28):
        """
        初始化
        :param length:验证码字符的长度
        :param width:验证码图片的宽度
        :param height:验证码图片的高度
        :param size:验证码字体的大小
        """
        self.length = length
        self.width = width
        self.height = height
        self.size = size

    def random_str(self):
        """
        随机字符串
        26个大小写字母和10个数字为源
        :return:随机字符串
        """

        # import string ctrl+鼠标左键点击import string中的string可以查看说明：
        # string.ascii_letters代表的是大小写字母，可以console打印演示
        source = string.ascii_letters + '0123456789'  # 字符串拼接

        return ''.join(random.sample(source, self.length))
        # import random,ctrl+鼠标左键点击import random中的random，找到sample方法，查看说明
        # 截取列表的指定长度的随机数，但是不会改变列表本身的排序，返回的是一个列表，通过join方法变成字符串。

    # 新增
    def random_color(self, start=0, end=255):
        """
        随机RGB颜色
        :param start: 起始值
        :param end: 结束值
        :return:tuple （r，g，b） # 可以页面展示颜色rgb值引出表示方法
        """
        res = (random.randint(start, end) for i in range(3))
        return tuple(res)  # 可以console打印演示

    def random_lines(self, draw):
        """
        绘制干扰线
        :param draw: draw对象
        :return:
        """
        for i in range(self.length):  # 画self.length条线，也就是4条线
            lines = [(random.randint(0, self.width), random.randint(0, self.height)) for i in
                     range(2)]  # console打印，xy轴决定一个点，两点连成一条线
            draw.line(list(lines), fill=self.random_color(64, 255), width=2)  # 将上面随机的两点用fill颜色连成一条宽度为2px的线

    def random_points(self, draw, rate):
        """
        绘制干扰点
        :param draw: draw对象
        :param rate: 出现频率
        :return:
        """
        for x in range(self.width):  # x轴取值
            for y in range(self.height):  # y轴取值
                if random.randint(1, 100) <= rate:  # 概率控制，随机数如果小于等于rate，用随机fill颜色画点
                    draw.point((x, y), fill=self.random_color(64, 255))

    def image_code(self):
        """
        生成验证码图片
        :return: tuple (图片,验证码)
        """
        # 创建Image对象
        image = Image.new('RGB', (self.width, self.height), (255, 255, 255))  # 白色背景图

        # 创建Font对象(字体对象)
        file = os.path.dirname(os.path.abspath(__file__))  # 返回当前文件所在目录的绝对（完整）路径I:\now\test\xf_mall\utils
        font = ImageFont.truetype(f'{file}/HYYakuHei-85W.ttf', self.size)  # 以 f 开头，包含的{}表达式在程序运行时会被表达式的值代替

        # 创建Draw对象
        draw = ImageDraw.Draw(image)

        self.random_lines(draw)
        self.random_points(draw, 15)

        # 验证码
        code = self.random_str()

        # 随机颜色验证码写到图片上
        for t in range(self.length):  # 将验证码中每个字符在(30 * t, 3)坐标处开始，用fill颜色，font字体画出
            draw.text((25 * t + 5, 3), code[t], font=font, fill=self.random_color(32, 127))

        # return image # 完成以上每个部分，都可以运行当前文件查看图片结果

        # 模糊滤镜
        image = image.filter(ImageFilter.BLUR)  # ImageFilter.BLUR为模糊滤波，处理之后的图像会整体变得模糊
        return image, code  # 为了后续的校验，把code也返回回去




if __name__ == '__main__':
    imgVerify = ImageVerify()
    img, code = imgVerify.image_code()
    with open('test.png', 'wb') as f:
        img.save(f)
    print(code)
